#!/usr/bin/python
# -*- coding: utf-8 -*-

# 
# find-delete
# Copyright (C) 2010 Elton Pereira <eltonplima@gmail.com>
# 
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# 

import os
import commands
import sys
import datetime
import re

from optparse import OptionParser
import ConfigParser

class FindDelete():

    def __init__(self):
        VERSION = "0.1"
        usage = "usage: %prog [options] arg"

        self.CONF_FILE = "find-delete.conf"

        self.search_paths = None # Store the search paths in configuration file.
        self.ignore_paths = None # Store the ignore paths in configuration file.
        self.delete_extensions = None # Store the extensions in configuration file.
        self.backup_path = None
        self.datetime_backup_path = None # Backup path with date and time.
        self.has_files = False
        self.searched_files = False # If false no search was also performed.
        self.current_backup_path = None
        self.backup_list = None # List of backups stored.

        self.optParser = OptionParser(usage, version="%prog " + VERSION)
        self.config = ConfigParser.RawConfigParser()

        self.output_find = None # Store the output of the find command.

    def _preserve_path(self, path):
        split_path = re.split('/', path)
        split_path.pop(len(split_path)-1) # remove the last element(file name).

        new_path = ''

        for i in split_path:
            new_path = new_path + i + '/'

        complete_path = self.current_backup_path + new_path

        if not os.path.exists(complete_path):
            try:
                os.makedirs(complete_path)
            except OSError as os_exception:
                pass

        return new_path

    def _move_file(self, source, destination):
        move_command = 'mv \"' + source + '\" \"' + destination + '\"'
        return commands.getstatusoutput(move_command)[0]

    def _copy_file(self, source, destination):
        copy_command = 'cp \"' + source + '\" \"' + destination + '\"'
        return commands.getstatusoutput(copy_command)[0]

    def _find_file(self):
        """ Search files based on patterns in configuration file(extensions)
        """
        paths = ' '.join(i for i in self.search_paths)

        i = 0
        pattern_delete = ' '

        for delete_extension in self.delete_extensions:
            pattern_delete += ' -iname *.' + delete_extension
            i += 1
            if i < len(self.delete_extensions):
                pattern_delete += ' -o'

        find_command = None

        if self.ignore_paths:
            ignore = ''
            for ignore_path in self.ignore_paths:
                ignore += ' -path ' + ignore_path + ' -prune -o'

            find_command = 'find ' + paths + ignore + ' -type f \(' +\
                pattern_delete + ' \)'
        else:
            self.find_command = 'find ' + paths + ' -type f \(' +\
                pattern_delete + ' \)'

        self.output_find = commands.getoutput(find_command)

        if self.output_find:
            self.has_files = True

        self.searched_files = True

    def _list_backups(self):
        """ Create a list of backups stored.
        """
        list_backup_command = 'ls ' + self.backup_path
        self.backup_list = commands.getoutput(list_backup_command)

    def print_list_backups(self, option, opt, value, parser):
        self._list_backups()
        print(self.backup_list)

    def _premanipulation_files(self):
        """ Create the basic backup directories structure.
        """
        if not self.searched_files:
            self._find_file()

        if not self.backup_path:
            print('Please inform a backup directory in configuration file.')
            sys.exit(1)

        # No create backup if files not found.
        if self.output_find:
            # Create a backup dir.
            if not os.path.exists(self.backup_path):
                os.makedirs(self.backup_path)

            self.datetime_backup_path = self.backup_path + '/' +\
                datetime.datetime.now().strftime('%d%m%Y%H%M')

            if not os.path.exists(self.datetime_backup_path):
                os.makedirs(self.datetime_backup_path)

            self.current_backup_path = self.datetime_backup_path
        else:
            print("No files to manipulate.")
            sys.exit(0)

    def _config_option_parser(self):
        """ Configure the OptionParser.
        """
        self.optParser.add_option(
            "-f",
            "--find",
            action="callback",
            callback=self.print_find_file,
            help="Only find and display files."
        )

        self.optParser.add_option(
            "-m",
            "--move",
            action="callback",
            callback=self.move_files,
            help="Moves the files insteat of deleting them."
        )

        self.optParser.add_option(
            "-c",
            "--copy",
            action="callback",
            callback=self.copy_files,
            help="Copy the files insteat of deleting them."
        )

        self.optParser.add_option(
            "-l",
            "--list",
            action="callback",
            callback=self.print_list_backups,
            help="List backups stored."
        )

        self.optParser.add_option(
            "-p",
            "--preserve",
            action="store_true",
            dest="preserve_path",
            default=True,
            help="Preserves the original path in backup dir(default option)."
        )

        self.optParser.add_option(
            "-P",
            "--dontpreserve",
            action="store_false",
            dest="preserve_path",
            help="Don't preserves the original path in backup dir."
        )

        (options, args) = self.optParser.parse_args()

        if not sys.argv[1:]:
            self.optParser.print_help()
            sys.exit(1)

    def _config_config(self):
        """ Configure the ConfigParser.
        """
        path_config_file = os.getcwd() + '/' + self.CONF_FILE

        if os.path.exists(path_config_file):
            self.config.read(path_config_file)
            try:
                self.search_paths = self.config.get\
                    ('search', 'paths').split(',')
                self.ignore_paths = self.config.get\
                    ('search', 'ignore_paths').split(',')
                self.delete_extensions = self.config.get\
                    ('delete', 'extensions').split(',')

                if len(self.config.get('delete', 'backup_path').split(',')) > 1:
                    sys.stderr.write('Error in configuration file.' + 
                        ' The backup_path contain more one directory.\n')
                    sys.exit(1)
                else:
                    self.backup_path = self.config.get('delete', 'backup_path')
            except ConfigParser.NoSectionError as exception:
                sys.stderr.write('%s\n' % exception.line)
                sys.exit(1)
        else:
            sys.stderr.write('Configuration file not found in: %s\n' %\
                path_config_file)
            sys.exit(1)

    def print_find_file(self, option, opt, value, parser):
        """ Print the list of files found.
        """
        if not self.searched_files:
            self._find_file()

        print(self.output_find)

    def move_files(self, option, opt, value, parser):
        self._premanipulation_files()

        output_find_list = self.output_find.split('\n')

        for file_found in output_find_list:
            if parser.values.preserve_path:
                preserve_path = self._preserve_path(file_found)
                move_to = self.datetime_backup_path + preserve_path
		if not os.path.isdir(file_found):
                    self._move_file(file_found, move_to)
            else:
		if not os.path.isdir(file_found):
                    self._move_file(file_found, self.datetime_backup_path)

    def copy_files(self, option, opt, value, parser):
        self._premanipulation_files()

        output_find_list = self.output_find.split('\n')

        for file_found in output_find_list:
            if parser.values.preserve_path:
                preserve_path = self._preserve_path(file_found)
                copy_to = self.datetime_backup_path + preserve_path
		if not os.path.isdir(file_found):
                    self._copy_file(file_found, copy_to)
            else:
		if not os.path.isdir(file_found):
                    self._copy_file(file_found, self.datetime_backup_path)

    def configure(self):
        self._config_config()
        self._config_option_parser()

if __name__ == "__main__":
    f = FindDelete()
    f.configure()


